"use strict"

import {Native} from './native.js'

/**
 * UDP接收数据格式枚举
 * @enum string
 * @readonly
 * @see Udp#bind
 * @see Udp#send
 */
const UdpDataFormat = {
    TEXT:"text",
    HEX:"hexString"
}

/**
 * UDP通讯。
 * ** version 4 更新**
 * - 删除了open函数，使用{@link Udp#bind}函数替换
 * - 删除了close函数，请调用{@link Udp#destroy}释放资源
 * - 删除了sendto函数，使用{@link Udp#send}函数替换
 * @version 4
 * @author GuoHua Liu
 * @copyright Copyright © 2019 GuoHua Liu. All rights reserved.
 * @example
 import {Udp,UdpDataFormat} from './udp'

 const myUdpServer = new Udp()

 function recvObserver(event) {
    const packet = event.data
    console.log("收到Udp包" + packet.data + "来自" + packet.remoteIp + ":" + packet.remotePort)
}

 myUdpServer.addRecvObserver(recvObserver, this)

 myUdpServer.bind(10000, UdpDataFormat.TEXT).then(()=>{
    console.log("创建Udp服务成功")
})

 // 当不使用的时候
 // myUdpServer.destroy()
 */


class Udp {
    /**
     * @private
     * @param {string} name
     * @param {function} onevent
     * @param {*} context
     */
    addObserver(name, onevent, context) {
        Native.getInstance().addObserver("udp/" + this.socket + "/" + name, onevent, context)
        return this;
    }

    /**
     * @private
     * @param {string} name
     * @param {function} onevent
     */
     removeObserver(name, onevent) {
         Native.getInstance().delObserver("udp/" + this.socket + "/" + name, onevent)
         return this;
    }


    /**
     * @callback UdpRecvObserver
     * @param {{data:{data:string,remoteIp:string,remotePort:number}}} event
     */

    /**
     * 添加观察者：接收UDP包
     * @since 2
     * @param {UdpRecvObserver} onevent
     * @param {*} context
     */
    addRecvObserver(onevent, context=null) {
        this.addObserver("recv", onevent, context)
        return this;
    }

    /**
     * 删除addRecvObserver注册的观察者
     * @since 2
     * @param {UdpRecvObserver|null} onevent
     */
     removeRecvObserver(onevent = null) {
        this.removeObserver("recv", onevent)
        return this;
    }

    /**
     * 移除所有的观察者
     * @since 2
     */
    removeAllObserver() {
        this.removeRecvObserver();
    }

    /**
     * 绑定本地端口
     * @since 4
     * @param {number} localPort 如果指定localPort可以做UDP服务端，不指定localPort或者=0可以做UDP客户端
     * @param {UdpDataFormat} recvDataFormat since 3, 可以是
     * - {@link UdpDataFormat.HEX} 接收到的数据(UdpRecvEventData#data)为hexString
     * - {@link UdpDataFormat.TEXT} 接收到的数据(UdpRecvEventData#data)为文本(utf-8编码)
     * @returns {Promise} 成功回调时无参数;失败回调携带`{errMsg,errCode}`格式错误参数，其中errCode可能是:
     * - 1 创建socket失败,
     * - 2 绑定端口失败,
     * - 3 socket处于打开状态，无法打开一个已经打开的socket
     * - 其他 未知错误
     */
    bind(localPort, recvDataFormat = UdpDataFormat.HEX) {
        return new Promise((resolve,reject)=>{
            if (this.socket <= 0) {
                reject({errMsg:"未成功创建通讯", errCode:1})
                return
            }

            Native.getInstance().callNative("udp", {
                "method":"open",
                "socket":this.socket,
                "localPort":localPort,
                "recvDataFormat":recvDataFormat
            }, true, ()=>{
                resolve()
            }, (error)=>reject(error));
        })
    }

    /**
     * 发送UDP包。需要先open。
     * @since 2
     * @param {string} sendData 需要发送的数据，需为hexString格式
     * @param {string} targetIp
     * @param {number} targetPort
     * @param {UdpDataFormat} dataFormat since 4，指定sendData的格式是hex还是text。
     * @returns {Promise} 成功回调时无参数;失败回调携带`{errMsg,errCode}`格式错误参数，其中errCode可能是:
     * - 1 未成功创建通讯
     * - 2 无效数据
     * - 2 发送数据失败
     * - 其他 未知错误
     */
    send(sendData, targetIp, targetPort, dataFormat=UdpDataFormat.HEX) {
        return new Promise((resolve,reject)=>{
            if (this.socket <= 0) {
                reject({errMsg:"未成功创建通讯", errCode:1})
                return
            }
            Native.getInstance().callNative("udp",
            {method:"sendto",
                data:sendData,
                socket:this.socket,
                targetIp:targetIp,
                targetPort:targetPort,
                dataFormat:dataFormat
            }, true,
            (result)=>resolve(result), (error)=>reject(error));
        })
    }

    /**
     * 构造UDP实例。当实例不再使用的时候，请使用{@link Udp#destroy}释放资源
     * @since 2
     */
    constructor() {
        this.socket = Native.getInstance().syncCallNative("udp", {method:"socket"}).socket
        if (this.socket <= 0) {
            alert("创建socket失败")
        }
    }

    /**
     * 在完全不使用Udp实例的时候调用该函数释放资源。
     * @since 3
     */
    destroy() {
        this.removeAllObserver()
        if (this.socket > 0) {
            Native.getInstance().syncCallNative("udp", {method:"close", socket:this.socket});
            this.socket = 0;
        }
    }
}

export {Udp,UdpDataFormat}



